home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / r_sprite.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  11KB  |  402 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // r_sprite.c
  21.  
  22. #include "quakedef.h"
  23. #include "r_local.h"
  24.  
  25. static int                clip_current;
  26. static vec5_t            clip_verts[2][MAXWORKINGVERTS];
  27. static int                sprite_width, sprite_height;
  28.  
  29. spritedesc_t            r_spritedesc;
  30.     
  31.  
  32. /*
  33. ================
  34. R_RotateSprite
  35. ================
  36. */
  37. void R_RotateSprite (float beamlength)
  38. {
  39.     vec3_t    vec;
  40.     
  41.     if (beamlength == 0.0)
  42.         return;
  43.  
  44.     VectorScale (r_spritedesc.vpn, -beamlength, vec);
  45.     VectorAdd (r_entorigin, vec, r_entorigin);
  46.     VectorSubtract (modelorg, vec, modelorg);
  47. }
  48.  
  49.  
  50. /*
  51. =============
  52. R_ClipSpriteFace
  53.  
  54. Clips the winding at clip_verts[clip_current] and changes clip_current
  55. Throws out the back side
  56. ==============
  57. */
  58. int R_ClipSpriteFace (int nump, clipplane_t *pclipplane)
  59. {
  60.     int        i, outcount;
  61.     float    dists[MAXWORKINGVERTS+1];
  62.     float    frac, clipdist, *pclipnormal;
  63.     float    *in, *instep, *outstep, *vert2;
  64.  
  65.     clipdist = pclipplane->dist;
  66.     pclipnormal = pclipplane->normal;
  67.     
  68. // calc dists
  69.     if (clip_current)
  70.     {
  71.         in = clip_verts[1][0];
  72.         outstep = clip_verts[0][0];
  73.         clip_current = 0;
  74.     }
  75.     else
  76.     {
  77.         in = clip_verts[0][0];
  78.         outstep = clip_verts[1][0];
  79.         clip_current = 1;
  80.     }
  81.     
  82.     instep = in;
  83.     for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
  84.     {
  85.         dists[i] = DotProduct (instep, pclipnormal) - clipdist;
  86.     }
  87.     
  88. // handle wraparound case
  89.     dists[nump] = dists[0];
  90.     Q_memcpy (instep, in, sizeof (vec5_t));
  91.  
  92.  
  93. // clip the winding
  94.     instep = in;
  95.     outcount = 0;
  96.  
  97.     for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
  98.     {
  99.         if (dists[i] >= 0)
  100.         {
  101.             Q_memcpy (outstep, instep, sizeof (vec5_t));
  102.             outstep += sizeof (vec5_t) / sizeof (float);
  103.             outcount++;
  104.         }
  105.  
  106.         if (dists[i] == 0 || dists[i+1] == 0)
  107.             continue;
  108.  
  109.         if ( (dists[i] > 0) == (dists[i+1] > 0) )
  110.             continue;
  111.             
  112.     // split it into a new vertex
  113.         frac = dists[i] / (dists[i] - dists[i+1]);
  114.             
  115.         vert2 = instep + sizeof (vec5_t) / sizeof (float);
  116.         
  117.         outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
  118.         outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
  119.         outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
  120.         outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
  121.         outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
  122.  
  123.         outstep += sizeof (vec5_t) / sizeof (float);
  124.         outcount++;
  125.     }    
  126.     
  127.     return outcount;
  128. }
  129.  
  130.  
  131. /*
  132. ================
  133. R_SetupAndDrawSprite
  134. ================
  135. */
  136. void R_SetupAndDrawSprite ()
  137. {
  138.     int            i, nump;
  139.     float        dot, scale, *pv;
  140.     vec5_t        *pverts;
  141.     vec3_t        left, up, right, down, transformed, local;
  142.     emitpoint_t    outverts[MAXWORKINGVERTS+1], *pout;
  143.  
  144.     dot = DotProduct (r_spritedesc.vpn, modelorg);
  145.  
  146. // backface cull
  147.     if (dot >= 0)
  148.         return;
  149.  
  150. // build the sprite poster in worldspace
  151.     VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
  152.     VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
  153.     VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
  154.     VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
  155.  
  156.     pverts = clip_verts[0];
  157.  
  158.     pverts[0][0] = r_entorigin[0] + up[0] + left[0];
  159.     pverts[0][1] = r_entorigin[1] + up[1] + left[1];
  160.     pverts[0][2] = r_entorigin[2] + up[2] + left[2];
  161.     pverts[0][3] = 0;
  162.     pverts[0][4] = 0;
  163.  
  164.     pverts[1][0] = r_entorigin[0] + up[0] + right[0];
  165.     pverts[1][1] = r_entorigin[1] + up[1] + right[1];
  166.     pverts[1][2] = r_entorigin[2] + up[2] + right[2];
  167.     pverts[1][3] = sprite_width;
  168.     pverts[1][4] = 0;
  169.  
  170.     pverts[2][0] = r_entorigin[0] + down[0] + right[0];
  171.     pverts[2][1] = r_entorigin[1] + down[1] + right[1];
  172.     pverts[2][2] = r_entorigin[2] + down[2] + right[2];
  173.     pverts[2][3] = sprite_width;
  174.     pverts[2][4] = sprite_height;
  175.  
  176.     pverts[3][0] = r_entorigin[0] + down[0] + left[0];
  177.     pverts[3][1] = r_entorigin[1] + down[1] + left[1];
  178.     pverts[3][2] = r_entorigin[2] + down[2] + left[2];
  179.     pverts[3][3] = 0;
  180.     pverts[3][4] = sprite_height;
  181.  
  182. // clip to the frustum in worldspace
  183.     nump = 4;
  184.     clip_current = 0;
  185.  
  186.     for (i=0 ; i<4 ; i++)
  187.     {
  188.         nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
  189.         if (nump < 3)
  190.             return;
  191.         if (nump >= MAXWORKINGVERTS)
  192.             Sys_Error("R_SetupAndDrawSprite: too many points");
  193.     }
  194.  
  195. // transform vertices into viewspace and project
  196.     pv = &clip_verts[clip_current][0][0];
  197.     r_spritedesc.nearzi = -999999;
  198.  
  199.     for (i=0 ; i<nump ; i++)
  200.     {
  201.         VectorSubtract (pv, r_origin, local);
  202.         TransformVector (local, transformed);
  203.  
  204.         if (transformed[2] < NEAR_CLIP)
  205.             transformed[2] = NEAR_CLIP;
  206.  
  207.         pout = &outverts[i];
  208.         pout->zi = 1.0 / transformed[2];
  209.         if (pout->zi > r_spritedesc.nearzi)
  210.             r_spritedesc.nearzi = pout->zi;
  211.  
  212.         pout->s = pv[3];
  213.         pout->t = pv[4];
  214.         
  215.         scale = xscale * pout->zi;
  216.         pout->u = (xcenter + scale * transformed[0]);
  217.  
  218.         scale = yscale * pout->zi;
  219.         pout->v = (ycenter - scale * transformed[1]);
  220.  
  221.         pv += sizeof (vec5_t) / sizeof (*pv);
  222.     }
  223.  
  224. // draw it
  225.     r_spritedesc.nump = nump;
  226.     r_spritedesc.pverts = outverts;
  227.     D_DrawSprite ();
  228. }
  229.  
  230.  
  231. /*
  232. ================
  233. R_GetSpriteframe
  234. ================
  235. */
  236. mspriteframe_t *R_GetSpriteframe (msprite_t *psprite)
  237. {
  238.     mspritegroup_t    *pspritegroup;
  239.     mspriteframe_t    *pspriteframe;
  240.     int                i, numframes, frame;
  241.     float            *pintervals, fullinterval, targettime, time;
  242.  
  243.     frame = currententity->frame;
  244.  
  245.     if ((frame >= psprite->numframes) || (frame < 0))
  246.     {
  247.         Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
  248.         frame = 0;
  249.     }
  250.  
  251.     if (psprite->frames[frame].type == SPR_SINGLE)
  252.     {
  253.         pspriteframe = psprite->frames[frame].frameptr;
  254.     }
  255.     else
  256.     {
  257.         pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
  258.         pintervals = pspritegroup->intervals;
  259.         numframes = pspritegroup->numframes;
  260.         fullinterval = pintervals[numframes-1];
  261.  
  262.         time = cl.time + currententity->syncbase;
  263.  
  264.     // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
  265.     // are positive, so we don't have to worry about division by 0
  266.         targettime = time - ((int)(time / fullinterval)) * fullinterval;
  267.  
  268.         for (i=0 ; i<(numframes-1) ; i++)
  269.         {
  270.             if (pintervals[i] > targettime)
  271.                 break;
  272.         }
  273.  
  274.         pspriteframe = pspritegroup->frames[i];
  275.     }
  276.  
  277.     return pspriteframe;
  278. }
  279.  
  280.  
  281. /*
  282. ================
  283. R_DrawSprite
  284. ================
  285. */
  286. void R_DrawSprite (void)
  287. {
  288.     int                i;
  289.     msprite_t        *psprite;
  290.     vec3_t            tvec;
  291.     float            dot, angle, sr, cr;
  292.  
  293.     psprite = currententity->model->cache.data;
  294.  
  295.     r_spritedesc.pspriteframe = R_GetSpriteframe (psprite);
  296.  
  297.     sprite_width = r_spritedesc.pspriteframe->width;
  298.     sprite_height = r_spritedesc.pspriteframe->height;
  299.  
  300. // TODO: make this caller-selectable
  301.     if (psprite->type == SPR_FACING_UPRIGHT)
  302.     {
  303.     // generate the sprite's axes, with vup straight up in worldspace, and
  304.     // r_spritedesc.vright perpendicular to modelorg.
  305.     // This will not work if the view direction is very close to straight up or
  306.     // down, because the cross product will be between two nearly parallel
  307.     // vectors and starts to approach an undefined state, so we don't draw if
  308.     // the two vectors are less than 1 degree apart
  309.         tvec[0] = -modelorg[0];
  310.         tvec[1] = -modelorg[1];
  311.         tvec[2] = -modelorg[2];
  312.         VectorNormalize (tvec);
  313.         dot = tvec[2];    // same as DotProduct (tvec, r_spritedesc.vup) because
  314.                         //  r_spritedesc.vup is 0, 0, 1
  315.         if ((dot > 0.999848) || (dot < -0.999848))    // cos(1 degree) = 0.999848
  316.             return;
  317.         r_spritedesc.vup[0] = 0;
  318.         r_spritedesc.vup[1] = 0;
  319.         r_spritedesc.vup[2] = 1;
  320.         r_spritedesc.vright[0] = tvec[1];
  321.                                 // CrossProduct(r_spritedesc.vup, -modelorg,
  322.         r_spritedesc.vright[1] = -tvec[0];
  323.                                 //              r_spritedesc.vright)
  324.         r_spritedesc.vright[2] = 0;
  325.         VectorNormalize (r_spritedesc.vright);
  326.         r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
  327.         r_spritedesc.vpn[1] = r_spritedesc.vright[0];
  328.         r_spritedesc.vpn[2] = 0;
  329.                     // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
  330.                     //  r_spritedesc.vpn)
  331.     }
  332.     else if (psprite->type == SPR_VP_PARALLEL)
  333.     {
  334.     // generate the sprite's axes, completely parallel to the viewplane. There
  335.     // are no problem situations, because the sprite is always in the same
  336.     // position relative to the viewer
  337.         for (i=0 ; i<3 ; i++)
  338.         {
  339.             r_spritedesc.vup[i] = vup[i];
  340.             r_spritedesc.vright[i] = vright[i];
  341.             r_spritedesc.vpn[i] = vpn[i];
  342.         }
  343.     }
  344.     else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT)
  345.     {
  346.     // generate the sprite's axes, with vup straight up in worldspace, and
  347.     // r_spritedesc.vright parallel to the viewplane.
  348.     // This will not work if the view direction is very close to straight up or
  349.     // down, because the cross product will be between two nearly parallel
  350.     // vectors and starts to approach an undefined state, so we don't draw if
  351.     // the two vectors are less than 1 degree apart
  352.         dot = vpn[2];    // same as DotProduct (vpn, r_spritedesc.vup) because
  353.                         //  r_spritedesc.vup is 0, 0, 1
  354.         if ((dot > 0.999848) || (dot < -0.999848))    // cos(1 degree) = 0.999848
  355.             return;
  356.         r_spritedesc.vup[0] = 0;
  357.         r_spritedesc.vup[1] = 0;
  358.         r_spritedesc.vup[2] = 1;
  359.         r_spritedesc.vright[0] = vpn[1];
  360.                                         // CrossProduct (r_spritedesc.vup, vpn,
  361.         r_spritedesc.vright[1] = -vpn[0];    //  r_spritedesc.vright)
  362.         r_spritedesc.vright[2] = 0;
  363.         VectorNormalize (r_spritedesc.vright);
  364.         r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
  365.         r_spritedesc.vpn[1] = r_spritedesc.vright[0];
  366.         r_spritedesc.vpn[2] = 0;
  367.                     // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
  368.                     //  r_spritedesc.vpn)
  369.     }
  370.     else if (psprite->type == SPR_ORIENTED)
  371.     {
  372.     // generate the sprite's axes, according to the sprite's world orientation
  373.         AngleVectors (currententity->angles, r_spritedesc.vpn,
  374.                       r_spritedesc.vright, r_spritedesc.vup);
  375.     }
  376.     else if (psprite->type == SPR_VP_PARALLEL_ORIENTED)
  377.     {
  378.     // generate the sprite's axes, parallel to the viewplane, but rotated in
  379.     // that plane around the center according to the sprite entity's roll
  380.     // angle. So vpn stays the same, but vright and vup rotate
  381.         angle = currententity->angles[ROLL] * (M_PI*2 / 360);
  382.         sr = sin(angle);
  383.         cr = cos(angle);
  384.  
  385.         for (i=0 ; i<3 ; i++)
  386.         {
  387.             r_spritedesc.vpn[i] = vpn[i];
  388.             r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
  389.             r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
  390.         }
  391.     }
  392.     else
  393.     {
  394.         Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
  395.     }
  396.  
  397.     R_RotateSprite (psprite->beamlength);
  398.  
  399.     R_SetupAndDrawSprite ();
  400. }
  401.  
  402.